#pragma once

#include <map>
#include <string>
#include <stack>

#include "Business/PendingMarket.h"

struct MatchItem
{
	MatchItem(int bp,int cp,int sp,int bq,int sq,int mcd)
		:buyPrice(bp),currentPrice(cp),sellPrice(sp),buyQuantity(bq),sellQuantity(sq),matched(mcd)
	{
	}
	int buyPrice;
	int currentPrice;
	int sellPrice;
	int buyQuantity;
	int sellQuantity;
	int matched;
};

struct Range
{
	Range(int s,int e)
		:start(s),end(e)
	{

	}
	int start;
	int end;
};

typedef std::vector<MatchItem> MatchItems;

struct MatchQuantity
{
	int quantity;
	int orderPrice;
	int dealPrice;
};

struct BuyItem
{
	BuyItem(int p, int s,int q)
		:price(p),sellQuantity(s),quantity(q)
	{
	}
	int price;
	int sellQuantity;
	int quantity;
};

struct SellItem
{
	SellItem(int p, int bq, int q, int b)
		:price(p),buyQuantity(bq),quantity(q),buyPrice(b)
	{

	}
	int price;
	int buyQuantity;
	int quantity;
	int buyPrice;
};

struct OrderItem
{
	OrderItem(int o,int d,int q)
		:orderPrice(o),dealPrice(d),quantity(q)
	{
	}
	int orderPrice;
	int dealPrice;
	int quantity;
};

typedef std::vector<OrderItem> OrderItems;

class ContractMatcher
{
public:
	typedef PendingMarkets::PendingMarketMap PendingMarketMap;
	typedef std::map<int,bool> PriceMap;

	ContractMatcher(int contract, int minPriceUnit);
	~ContractMatcher(){}

	void LogPendingOrders();
	void LogMatchItems();

	void Clear();
	ContractMatcher& Update(PendingMarket const& pendingMarket);
	ContractMatcher& Buy(int price, int quantity);
	ContractMatcher& Sell(int price, int quantity);
	ContractMatcher& AddBuy(int price, int quantity);
	ContractMatcher& AddSell(int price, int quantity);
	int Match();

	void GenerateItems();

	MatchItems const& GetAllItems() const { return m_allItems; }
	OrderItems const& GetBuyOrderItems() const { return m_buyOrderItems; }
	OrderItems const& GetSellOrderItems() const { return m_sellOrderItems; }

	int GetOpenItemIndex() const {return m_matchItems.size() - 1;}

	PendingMarketMap const& GetBuys() {return m_markets.GetBuys();}
	PendingMarketMap const& GetSells() {return m_markets.GetSells();}
private:
	int m_contract;
	int m_minPriceUnit;

	PendingMarkets m_markets;

	MatchItems m_matchItems;
	MatchItems m_allItems;
	OrderItems m_buyOrderItems;
	OrderItems m_sellOrderItems;

	PendingMarketMap::const_reverse_iterator m_last_bi;
	PendingMarketMap::const_iterator m_last_si;

	void GenerateMatchItems(PendingMarketMap::const_reverse_iterator &buyIter, PendingMarketMap::const_iterator &sellIter,PendingMarketMap::const_reverse_iterator &last_bi, PendingMarketMap::const_iterator &last_si);
	void AdjustMatchPrice(MatchItem &lastItem, PendingMarketMap::const_reverse_iterator buyIter, PendingMarketMap::const_iterator sellIter, PendingMarketMap::const_reverse_iterator last_bi, PendingMarketMap::const_iterator last_si);
	bool NextBuyGreaterSell(PendingMarketMap::const_reverse_iterator last_bi,PendingMarketMap::const_iterator last_si) const;
	bool BuyGreaterNextSell(PendingMarketMap::const_reverse_iterator last_bi,PendingMarketMap::const_iterator last_si) const;
	void GenerateAllItems(PendingMarketMap::const_reverse_iterator last_bi, PendingMarketMap::const_iterator last_si);
	void NextBuy(PendingMarketMap::const_reverse_iterator& bi, PendingMarketMap::const_reverse_iterator& end, int& bp, int& bq);
	void NextSell(PendingMarketMap::const_iterator& si,PendingMarketMap::const_iterator& end, int& sp, int& sq);

	void GenerateBuys(PendingMarketMap::const_reverse_iterator last_bi);
	void GenerateBuyPrices(PendingMarketMap::const_reverse_iterator bi,PriceMap& out_bps);
	void GenerateBuyQuantity(int buyPrice,bool moreFlag);

	void GenerateSells(PendingMarketMap::const_iterator last_si);
	void GenerateSellPrices(PendingMarketMap::const_iterator si,PriceMap& out_sps);
	void GenerateSellQuantity(int sellPrice,bool moreFlag);
};


class ContractMatcheres
{
public:
	ContractMatcheres();
	~ContractMatcheres();
	void Clear();
	void Update(PendingMarket const& pendingMarket);
	void AddBuy(int contract,int price,int quantity);
	void AddSell(int contract,int price,int quantity);
	ContractMatcher& AddMatcher(int contract, int minPirceUnit);
	ContractMatcher& GetMatcher(int contract);
	bool HasContract(int contract) const { return NotNull(m_matcheres[contract]);}
private:
	ContractMatcher* m_matcheres[MAX_MARKET_COUNT];
};